package com.tao.media.service.jobHandler;
import com.tao.base.utils.Mp4VideoUtil;
import com.tao.media.domain.pojo.MediaProcess;
import com.tao.media.service.impl.MediaFilesServiceImpl;
import com.tao.media.service.impl.MediaProcessServiceImpl;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import io.minio.DownloadObjectArgs;
import io.minio.MinioClient;
import io.minio.UploadObjectArgs;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * <p>
 * 视频处理任务
 * </p>
 *
 * @author taohongrun
 * @since 2024/11/14
 */
@RequiredArgsConstructor
@Slf4j
@Component
public class VideoTask {
    private final MediaFilesServiceImpl mediaFilesService;
    private final MediaProcessServiceImpl mediaProcessService;
    private final MinioClient minioClient;

    @Value("${videoprocess.ffmegpath}")
    String ffmpegpath;
    @XxlJob("videoJobHandler")
    public void videoJobHandler() {
        // 确定可用 CPU 核数
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        int threadPoolSize = availableProcessors / 2;
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(threadPoolSize);
        try {
            // 分片参数
            int shardIndex = XxlJobHelper.getShardIndex();
            int shardTotal = XxlJobHelper.getShardTotal();
            log.info("......index:{},total:{}......", shardIndex, shardTotal);
           
            // 查询需要处理的任务
            List<MediaProcess> mediaProcesses = mediaProcessService.getProcess(shardTotal, shardIndex, threadPoolSize);
            log.info("需要处理的任务为:{}", mediaProcesses);
            // 检查任务数量
            int size = mediaProcesses.size();
            log.info("取出待处理视频任务{}条", size);
            if (size <= 0) {
                // 没有任务，直接返回
                return;
            }

            mediaProcesses.forEach(mediaProcess -> {
                executorService.submit(() -> {
                    processMedia(mediaProcess);
                });
            });
        } catch (Exception e) {
            log.error("处理视频任务时发生异常: {}", e.getMessage(), e);
        } finally {
            if (executorService != null) {
                executorService.shutdown(); // 关闭线程池
            }
        }
    }
    private void processMedia(MediaProcess mediaProcess) {
        Long mediaProcessId = mediaProcess.getId();
        // 开启任务，未抢到锁证明该线程无效
        if (!mediaProcessService.startProcess(mediaProcessId)) return;
        // 获取文件信息
        String bucket = mediaProcess.getBucket();
        String filePath = mediaProcess.getFilePath();
        String fileId = mediaProcess.getFileId();
        String filename = mediaProcess.getFilename();
        // 下载文件
        File originalFile = downloadFromMinio(bucket, filePath);
        log.info("信息下载到:{}", originalFile.getAbsolutePath());
        if (originalFile == null) {
            log.debug("下载待处理文件失败, originalFile: {}", mediaProcess.getBucket().concat(mediaProcess.getFilePath()));
            mediaProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", fileId, null, "下载待处理文件失败");
            return;
        }
        File mp4File = null;
        try {
            mp4File = File.createTempFile("mp4", ".mp4");
        } catch (IOException e) {
            log.error("创建mp4临时文件失败: {}", e.getMessage());
            mediaProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", fileId, null, "创建mp4临时文件失败");
            return;
        }
        // 视频处理结果
        String result;
        try {
            log.info(".....开始转码");
            Mp4VideoUtil videoUtil = new Mp4VideoUtil(ffmpegpath, originalFile.getAbsolutePath(), mp4File.getName(), mp4File.getAbsolutePath());
            result = videoUtil.generateMp4();
        } catch (Exception e) {
            log.error("处理视频文件:{},出错:{}", mediaProcess.getFilePath(), e.getMessage());
            mediaProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", fileId, null, "转码失败: " + e.getMessage());
            return;
        }
        if (!"success".equals(result)) {
            log.error("处理视频失败, 视频地址:{}, 错误信息:{}", bucket + filePath, result);
            mediaProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", fileId, null, result);
            return;
        }
        // 上传视频
        String objectName = getFilePath(fileId, ".mp4");
        String url = "/" + bucket + "/" + objectName;
        try {
            mediaFilesService.uploadFilesToMinio(mp4File.getAbsolutePath(), "video/mp4", bucket, objectName);
            mediaProcessService.saveProcessFinishStatus(mediaProcess.getId(), "2", fileId, url, null);
            originalFile.delete();
            mp4File.delete();
        } catch (Exception e) {
            log.error("上传视频失败或入库失败, 视频地址:{}, 错误信息:{}", bucket + objectName, e.getMessage());
            mediaProcessService.saveProcessFinishStatus(mediaProcess.getId(), "3", fileId, null, "处理后视频上传或入库失败: " + e.getMessage());
        }
    }
    private File downloadFromMinio(String bucket, String objectPath) {
        try {
            String filePath = "D:\\mp4Temp\\" + objectPath.substring(objectPath.lastIndexOf('/') + 1);
            minioClient.downloadObject(DownloadObjectArgs.builder()
                    .bucket(bucket)
                    .object(objectPath)
                    .filename(filePath)
                    .build());
            return new File(filePath);
        } catch (Exception e) {
            log.error("下载文件失败: {}", e.getMessage());
            return null; // 返回 null 以表示下载失败
        }
    }
    private String getFilePath(String fileMd5, String fileExt) {
        return fileMd5.substring(0, 1) + "/" + fileMd5.substring(1, 2) + "/" + fileMd5 + "/" + fileMd5 + fileExt;
    }
}